﻿using System;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Reflection;

namespace DebIt.Common.Model
{
    public class DbStoredItem : INotifyPropertyChanged, INotifyPropertyChanging
    {

        #region events

        private PropertyChangingEventHandler _propertyChangingEvent;
        private PropertyChangedEventHandler _propertyChangedEvent;

        #endregion


        #region methods

        public event PropertyChangingEventHandler PropertyChanging
        {
            add { _propertyChangingEvent += value; }
            remove { _propertyChangingEvent -= value; }
        }

        public event PropertyChangedEventHandler PropertyChanged
        {
            add { _propertyChangedEvent += value; }
            remove { _propertyChangedEvent -= value; }
        }

        protected void SendPropertyChanged<T>(Expression<Func<T>> expression)
        {
            var propertyName = ExtractPropertyName(expression);
            if (_propertyChangedEvent != null)
            {
                _propertyChangedEvent(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        
        protected void SendPropertyChanging<T>(Expression<Func<T>> expression)
        {
            var propertyName = ExtractPropertyName(expression);
            if (_propertyChangingEvent != null)
            {
                _propertyChangingEvent(this, new PropertyChangingEventArgs(propertyName));
            }
        }

        private string ExtractPropertyName<T>(Expression<Func<T>> expression)
        {
            if (expression == null)
            {
                throw new ArgumentNullException("expression");
            }

            var memberExpression = expression.Body as MemberExpression;
            if (memberExpression == null)
            {
                throw new ArgumentException("It is not a Member-Lamda-Expressio, its a MemberExpression.", "expression");
            }

            var property = memberExpression.Member as PropertyInfo;
            if (property == null)
            {
                throw new ArgumentException("The Member-Expressio dont use properties.", "expression");
            }

            if (!property.DeclaringType.IsAssignableFrom(GetType()))
            {
                throw new ArgumentException("the propertie is a wrong type.", "expression");
            }

            var getMethod = property.GetGetMethod(true);
            if (getMethod == null)
            {
                throw new ArgumentException("The properti dosn't suport a get method", "expression");
            }

            if (getMethod.IsStatic)
            {
                throw new ArgumentException("The propertie is static.", "expression");
            }

            return memberExpression.Member.Name;
        }

        #endregion
    }
}
